.386
.model flat,stdcall
option casemap:none

include windows.inc
include kernel32.inc
include user32.inc
include shlwapi.inc
include dbghelp.inc

.data
kDumpFmt dw "%","s","-","%","0","4","d","%","0","2","d","%","0","2","d","%","0","2","d","%","0","2","d","%","0","2","d",".","d","m","p", 0

.code
;**************************************************************
; MiniDumpCallback
MiniDumpCallback proc stdcall uses ebx edx, pParam:dword, pCallbackInput:dword, pCallbackOutput:dword
    local bRet:dword
    local ulModuleWriteFlags:dword
    mov bRet, FALSE
    mov ebx, dword ptr [pCallbackInput]
    mov edx, pCallbackOutput
    mov eax, dword ptr [edx]
    mov ulModuleWriteFlags, eax
    assume ebx:ptr MINIDUMP_CALLBACK_INPUT
    .while TRUE
        .break .if ebx==NULL || edx==NULL
        .if [ebx].CallbackType==IncludeModuleCallback
            mov bRet, TRUE ; Include the module into the dump
        .elseif [ebx].CallbackType==IncludeThreadCallback
            mov bRet, TRUE ; Include the thread into the dump
        .elseif [ebx].CallbackType==ModuleCallback
			and eax, ModuleReferencedByMemory
            .if !eax
                ; [edx].ModuleWriteFlags &= (~ModuleWriteModule)
                mov eax, ulModuleWriteFlags
                and eax, 0FFFFFFFEh ; ~ModuleWriteModule
                mov dword ptr[edx], eax
            .endif
            mov bRet, TRUE
        .elseif [ebx].CallbackType==ThreadCallback
            mov bRet, TRUE ; Include all thread information into the minidump
        .elseif [ebx].CallbackType==ThreadExCallback
            mov bRet, TRUE ; Include this information
        .elseif [ebx].CallbackType==MemoryCallback
            mov bRet, FALSE ; We do not include any information here
        .elseif [ebx].CallbackType==CancelCallback
            ;mov bRet, TRUE
        .endif
        .break
    .endw
    assume ebx:nothing
    mov eax, bRet
    ret
MiniDumpCallback endp
;**************************************************************

;**************************************************************
; CreateMiniDump
CreateMiniDump proc stdcall pException:dword
    local szDumpName[256]:dword
    local szAppPath[256]:dword
    local hFile:dword
    local hProcess:dword
    local dwPid:dword
    local dwFlag:dword
    local pExceptionParam:dword
    local stTime:SYSTEMTIME
	local mdei:MINIDUMP_EXCEPTION_INFORMATION
    local mci:MINIDUMP_CALLBACK_INFORMATION
    invoke GetLocalTime, addr stTime
    invoke GetModuleFileNameW, NULL, addr szAppPath, 256
    invoke PathRemoveExtension, addr szAppPath
    invoke wsprintfW, \
            addr szDumpName, \
            addr kDumpFmt, \
            addr szAppPath, \
            [stTime].wYear, \
            [stTime].wMonth, \
            [stTime].wDay, \
            [stTime].wHour, \
            [stTime].wMinute, \
            [stTime].wSecond
    invoke CreateFile, \
                addr szDumpName, \
                GENERIC_READ or GENERIC_WRITE, \
                FILE_SHARE_READ or FILE_SHARE_WRITE, \
                NULL, \
                CREATE_ALWAYS, \
                FILE_ATTRIBUTE_NORMAL, \
                NULL
    .if !eax
        jmp @F
    .endif
    mov hFile, eax
    invoke GetCurrentThreadId
    mov [mdei].ThreadId, eax
    push pException
    pop [mdei].ExceptionPointers
    mov [mdei].ClientPointers, FALSE
    mov [mci].CallbackRoutine, offset MiniDumpCallback
	mov [mci].CallbackParam, 0
	mov dwFlag, MiniDumpWithIndirectlyReferencedMemory
	or dwFlag, MiniDumpScanMemory
	invoke GetCurrentProcess
	mov hProcess, eax
	invoke GetCurrentProcessId
	mov dwPid, eax
	.if pException!=NULL
	    lea eax, mdei
	    mov pExceptionParam, eax
    .else
        mov pExceptionParam, NULL
	.endif
	invoke MiniDumpWriteDump, \
	        hProcess, \
	        dwPid, \
	        hFile, \
	        dwFlag, \
	        pExceptionParam, \
	        NULL, \
	        addr mci
	invoke CloseHandle, hFile
@@:
    mov eax, EXCEPTION_CONTINUE_SEARCH
    ret
CreateMiniDump endp
;**************************************************************

end
